package org.example.study4;
/**
 * 通过细粒度锁减少同步范围，平衡线程安全与性能。
 * 细粒度锁，使用synchronized 修饰代码块，把对共享变量的修改加锁执行（缩小锁范围）。
 * 实际意义：展示了在多线程编程中，如何通过合理缩小同步范围提升性能，同时保持数据一致性。
 */
public class Demo_402 {
    public static void main(String[] args) throws InterruptedException {
        // 初始化累加对象
        Counter402 counter = new Counter402(); // 创建 Counter402 实例

        // 创建两个线程对同一个变量进行累加
        // 线程1
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.increase(); // 调用包含同步块的累加方法
            }
        });

        // 线程2
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.increase(); // 同上
            }
        });

        // 启动线程
        t1.start();
        t2.start();

        // 等待线程执行完成
        t1.join();
        t2.join();

        // 输出结果（必为 10 万）
        System.out.println("count = " + counter.count);
    }
}



class Counter402 {
    public int count = 0; // 共享变量

    public void increase() {
        // ----------------------
        // 非同步区域（可并行执行）
        // 例如：
        // 1. 查询数据库 selectAll(); → 可并行
        // 2. 数据处理 build(); → 可并行
        // ----------------------

        // ----------------------
        // 同步区域（仅保护共享变量修改）-- 串行执行
        synchronized (this) { // 锁定当前对象
            count++; // 原子操作
        }
        // ----------------------

        // ----------------------
        // 其他非同步操作（可并行执行）
        // 例如：日志记录、非共享变量操作等
        // ----------------------
    }
}

// 运行：count = 100000
/*

Demo_401 的 synchronized 方法会锁住整个方法，即使方法中有非共享变量操作（如日志、数据库查询），也会强制串行执行。
Demo_402 的 synchronized 代码块仅锁定共享变量操作，其他代码可并行执行，提升性能。
只对必须同步的代码（count++）加锁，其他无关操作（如查询、计算）允许并发执行，这样锁的持有时间更短，减少线程等待
synchronized (this) 使用当前对象作为锁，与 synchronized 方法等效，但控制更灵活*/



/*总结：关于synchronized
1.被synchronized修饰的代码会变成串行执行
2.synchronized可以去修饰方法，也可以修饰代码块
3.被synchronized修饰的代码并不是一次性在CPU上执行完，而是中途可能会被CPU调度走
当所有的指令执行完成之后才会释放锁
4.只给一个线程加锁，也会出现线程安全问题
*/